class Individual:
    def __init__(self, genes): ## Construtor da classe
        assert(len(genes) > 3) # Garante que todo indivíduo tenha, pelo menos, 3 genes.
        self.genes = genes     # Atributo principal de um indivíduo: Gene.
        self.__reset_params()  # Zera atributos.

    """
    Troca a ordem dos genes para simular uma MUTAÇÃO.
    """
    def swap(self, gene_1, gene_2):
        self.genes[0]
        a, b = self.genes.index(gene_1), self.genes.index(gene_2)
        self.genes[b], self.genes[a] = self.genes[a], self.genes[b]
        self.__reset_params()


    """
    Adiciona um gene ao indivíduo.
    """
    def add(self, gene):
        self.genes.append(gene)
        self.__reset_params()

    @property
    def fitness(self):
        if self.__fitness == 0:
            self.__fitness = 1 / self.travel_cost  # Com base no travel_cost.
        return self.__fitness

    @property
    def travel_cost(self):
        if self.__travel_cost == 0:
            for i in range(len(self.genes)):
                origin = self.genes[i] # Loop: Todas as origens possíveis.
                if i == len(self.genes) - 1: # Estamos na última origem?
                    dest = self.genes[0]     # ... Então nosso destino agora é a primeira cidade (distância da última à primeira).
                else:
                    dest = self.genes[i+1]   # Senão, próximo destino dentre todos os possíveis.

                self.__travel_cost += origin.get_distance_to(dest) # Soma travel_cost com a distância do gene (cidade) da atual origem ao gene (cidade) do atual destino.

        return self.__travel_cost

    """
    Zera todos os atributos do indivíduos.
    """
    def __reset_params(self):
        self.__travel_cost = 0
        self.__fitness = 0
